﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Threading;
using System.Diagnostics;
using System.Net;
using System.ComponentModel;

namespace XiaLastorm.Sharpshooter.Server
{
	/// <summary>
	/// 客户端管理器
	/// </summary>
	public class ClientManager : IDisposable, INotifyPropertyChanged
	{
		/// <summary>
		/// 已登录用户
		/// </summary>
		public static SortedSet<User> UsersLoggedIn = new SortedSet<User>();
		
		private User user;
		/// <summary>
		/// 获取或设置本客户端的当前用户
		/// </summary>
		public User User
		{
			get { return user; }
			protected set
			{
				if (user != value)
				{
					user = value;
					RaisePropertyChangedEvent("User");
				}
			}
		}
		/// <summary>
		/// 客户端地址
		/// </summary>
		public EndPoint ClientAddress { get; protected set; }
		/// <summary>
		/// 获取或设置服务器通与客户端通信时使用的套接字
		/// </summary>
		protected Socket Socket { get; set; }
		/// <summary>
		/// 获取或设置客户端管理器使用的线程
		/// </summary>
		protected Thread Thread { get; set; }
		/// <summary>
		/// 获取或设置消息发送队列
		/// </summary>
		public Queue<Message> MessageQueue { get; protected set; }

		/// <summary>
		/// 生成 <see cref="ClientManager"/> class 的新实例。
		/// </summary>
		/// <param name="socket">服务器通与客户端通信时使用的套接字</param>
		public ClientManager(Socket socket)
		{
			Socket = socket;
			Socket.SendBufferSize = 0x1000000;
			Socket.ReceiveBufferSize = 0x1000000;
			ClientAddress = Socket.RemoteEndPoint;
			MessageQueue = new Queue<Message>();
		}

		/// <summary>
		/// 当用户成功登录时发生。
		/// </summary>
		public event EventHandler<UserEventArgs> UserLoggedIn;
		/// <summary>
		/// 引发用户成功登录事件。
		/// </summary>
		/// <param name="user">用户</param>
		protected void RaiseUserLoggedInEvent(User user)
		{
			if (UserLoggedIn != null)
				UserLoggedIn(this, new UserEventArgs(user));
		}

		/// <summary>
		/// 当用户成功注销时发生。
		/// </summary>
		public event EventHandler<UserEventArgs> UserLoggedOut;
		/// <summary>
		/// 引发用户成功注销事件。
		/// </summary>
		/// <param name="user">用户</param>
		protected void RaiseUserLoggedOutEvent(User user)
		{
			if (UserLoggedOut != null)
				UserLoggedOut(this, new UserEventArgs(user));
		}
		/// <summary>
		/// 当收到用户对另一用户发送的消息时发生。
		/// </summary>
		public event EventHandler<UserToUserMessageEventArgs> UserToUserMessageReceived;
		/// <summary>
		/// 引发收到用户对另一用户发送的消息事件。
		/// </summary>
		/// <param name="message">消息</param>
		protected void RaiseUserToUserMessageReceivedEvent(UserToUserMessage message)
		{
			if (UserToUserMessageReceived != null)
			{
				UserToUserMessageReceived(this, new UserToUserMessageEventArgs(message));
			}
		}

		/// <summary>
		/// 当管理器停止工作时发生。
		/// </summary>
		public event EventHandler Stoped;
		/// <summary>
		/// 引发管理器停止工作事件。
		/// </summary>
		protected void RaiseStopedEvent()
		{
			if (Stoped != null)
				Stoped(this, EventArgs.Empty);
		}
		/// <summary>
		/// 当收到消息时发生。
		/// </summary>
		public event EventHandler<MessageEventArgs> MessageReceived;
		/// <summary>
		/// 引发收到消息事件。
		/// </summary>
		/// <param name="message">消息</param>
		protected void RaiseMessageReceivedEvent(Message message)
		{
			if (MessageReceived != null)
				MessageReceived(this, new MessageEventArgs(message));
		}
		/// <summary>
		/// 当发送完消息时发生。
		/// </summary>
		public event EventHandler<MessageEventArgs> MessageSent;
		/// <summary>
		/// 引发发送完消息事件。
		/// </summary>
		/// <param name="message">消息</param>
		protected void RaiseMessageSentEvent(Message message)
		{
			if (MessageSent != null)
				MessageSent(this, new MessageEventArgs(message));
		}
		/// <summary>
		/// 用于线程同步的对象
		/// </summary>
		private object lockObject = new object();
		/// <summary>
		/// 是否应该停止工作
		/// </summary>
		private bool shouldStop = false;
		private ManualResetEvent manualEvent;
		/// <summary>
		/// 客户端管理器状态枚举
		/// </summary>
		public enum ManagerState { BeforeStart = 0, Started, Stoped };
		private ManagerState state;
		/// <summary>
		/// 状态
		/// </summary>
		public ManagerState State
		{
			get
			{
				lock (lockObject)
				{
					return state;
				}
			}
			protected set
			{
				lock (lockObject)
				{
					if (state == value) return;
					state = value;
				}
				switch (State)
				{
					case ManagerState.BeforeStart:
						break;
					case ManagerState.Started:
						break;
					case ManagerState.Stoped:
						RaiseStopedEvent();
						break;
					default:
						break;
				}
			}
		}

		/// <summary>
		/// 验证管理器还未开始工作。
		/// </summary>
		protected void ValidateBeforeOpen()
		{
			if (State == ManagerState.Started)
				throw new Exception("管理器正在工作");
			if (State == ManagerState.Stoped)
				throw new Exception("管理器已停止工作");
		}

		/// <summary>
		/// 验证管理器正在工作。
		/// </summary>
		protected void ValidateOpened()
		{
			if (State == ManagerState.BeforeStart)
				throw new Exception("管理器还未开始工作");
			if (State == ManagerState.Stoped)
				throw new Exception("管理器已停止工作");
		}
		/// <summary>
		/// 验证管理器已停止工作。
		/// </summary>
		protected void ValidateClosed()
		{
			if (State == ManagerState.BeforeStart)
				throw new Exception("管理器还未开始工作");
			if (State == ManagerState.Started)
				throw new Exception("管理器正在工作");
		}

		/// <summary>
		/// 开始处理与客户端的通信
		/// </summary>
		public void Start()
		{
			//防止重复使用
			ValidateBeforeOpen();
			State = ManagerState.Started;

			Thread = new Thread(new ThreadStart(() =>
				{
					while (true)
					{
						//发送尚未发送的消息
						while (MessageQueue.Count > 0)
						{
							Message message = MessageQueue.Dequeue();
							try
							{
								SendMessageToClient(message);
							}
							catch { }					//服务器不能崩溃，消息发送出错就算了
						}

						//检查是否应该停止
						bool flag = false;
						lock (lockObject)
						{
							if (shouldStop)
							{
								Socket.Close();
								Socket = null;
								Thread = null;
								flag = true;
							}
						}
						if (flag)
						{
							State = ManagerState.Stoped;
							if (manualEvent != null)
								manualEvent.Set();
							break;
						}

						//接收新消息
						if (Socket.Poll(100, SelectMode.SelectRead))		//查看是否有新消息（如果客户端已关闭，仍然返回true）
						{
							try
							{
								Message message = ReceiveMessageFromClient();
								ProcessMessage(message);
							}
							catch
							{
								lock (lockObject)
								{
									shouldStop = true;
								}
							}
						}
					}
				}));
			Thread.Start();
		}

		/// <summary>
		/// 处理客户端发来的消息
		/// </summary>
		/// <param name="message">消息</param>
		/// <returns>如果消息合法并被成功处理，返回true；否则返回false</returns>
		protected bool ProcessMessage(Message message)
		{
			if (message == null)							//如果客户端已关闭，或者发送过来的数据不是一个消息，则message为null，这时应该中止工作
			{
				lock (lockObject)
				{
					shouldStop = true;
				}
				return false;
			}
			else if (message is LogInMessage)				//用户登录
			{
				var logInMessage = message as LogInMessage;
				if (User != null)
				{
					MessageQueue.Enqueue(new ErrorMessage("您已经登录", message));
					return true;
				}
				else
				{
					try
					{
						User = new User(logInMessage.Username);
					}
					catch (Exception ex)
					{
						MessageQueue.Enqueue(new ErrorMessage(ex.Message, message));
						return true;
					}
					if (UsersLoggedIn.Contains(User))
					{
						User = null;
						MessageQueue.Enqueue(new ErrorMessage(string.Format("{0}已登录", logInMessage.Username), message));
						return true;
					}
					else
					{
						MessageQueue.Enqueue(new LogInResultMessage(User));
						RaiseUserLoggedInEvent(User);
						return true;
					}
				}
			}
			else if (message is LogOutMessage)				//用户注销
			{
				if (User == null)
					MessageQueue.Enqueue(new ErrorMessage("您尚未登录", message));
				var logOutMessage = message as LogOutMessage;
				MessageQueue.Enqueue(new LogOutResultMessage(true));
				if (User != null)
				{
					User temp = User;
					User = null;
					RaiseUserLoggedOutEvent(temp);
				}
				return true;
			}
			else if (message is ClientQuitMessage)			//客户端退出
			{
				var clientQuitMessage = message as ClientQuitMessage;
				lock (lockObject)
				{
					shouldStop = true;
				}
				return true;
			}
			else if (message is UserToUserMessage)			//发给另一用户的消息
			{
				var userToUserMessage = message as UserToUserMessage;
				if (userToUserMessage.From == this.User && userToUserMessage.To != null && userToUserMessage.From != userToUserMessage.To && ClientManager.UsersLoggedIn.Contains(userToUserMessage.To))
				{
					RaiseUserToUserMessageReceivedEvent(userToUserMessage);
					return true;
				}
				else
				{
					MessageQueue.Enqueue(new ErrorMessage("消息来源或目标非法", message));
					return true;
				}
			}
			else											//其他消息，不处理
			{
				return false;
			}
		}

		/// <summary>
		/// 发送好友列表
		/// </summary>
		/// <param name="friends">好友列表</param>
		public void SendFriendsList(List<User> friends)
		{
			ValidateOpened();
			MessageQueue.Enqueue(new RefreshFriendsListMessage(friends));
		}

		/// <summary>
		/// 让管理器停止工作，并回收资源
		/// </summary>
		public void Stop()
		{
			Dispose();
		}

		/// <summary>
		/// 给客户端发送消息
		/// </summary>
		/// <param name="message">要发送的消息</param>
		protected void SendMessageToClient(Message message)
		{
			MessageHelper.Send(Socket, message);
			RaiseMessageSentEvent(message);
		}

		/// <summary>
		/// 从客户端接收消息
		/// </summary>
		/// <returns>接收到的消息</returns>
		protected Message ReceiveMessageFromClient()
		{
			Message message = MessageHelper.Receive(Socket);
			if (message != null)
				RaiseMessageReceivedEvent(message);
			return message;
		}

		/// <summary>
		/// 执行与释放或重置非托管资源相关的应用程序定义的任务。
		/// </summary>
		public void Dispose()
		{
			lock (lockObject)
			{
				if (shouldStop) return;
				shouldStop = true;
				manualEvent = new ManualResetEvent(false);
			}
			manualEvent.WaitOne();
			ValidateClosed();
			Debug.Assert(Thread == null && Socket == null);
			GC.SuppressFinalize(this);
		}

		/// <summary>
		/// 析构函数
		/// </summary>
		~ClientManager()
		{
			Dispose();
		}

		public override string ToString()
		{
			StringBuilder sb = new StringBuilder();
			if (User != null)
				sb.Append(User);
			if (sb.Length > 0)
			{
				sb.Append(" (");
				sb.Append(ClientAddress);
				sb.Append(")");
			}
			else
			{
				sb.Append(ClientAddress);
			}
			return sb.ToString();
		}

		/// <summary>
		/// 在更改属性值时发生。
		/// </summary>
		public event PropertyChangedEventHandler PropertyChanged;
		/// <summary>
		/// 引发更改属性值事件。
		/// </summary>
		/// <param name="propertyName">已更改的属性名</param>
		protected void RaisePropertyChangedEvent(string propertyName)
		{
			if (PropertyChanged != null)
				PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
		}
	}
}